﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FileHelpers;
using System.Globalization;

namespace MoneyWentWhere.Utils
{
    /// <summary>
    /// Converts a money amount, with padding support.
    /// Amount will be formatted as 0.00 (always two decimals).
    /// </summary>
    class AmountConverter : ConverterBase
    {
        protected override bool CustomNullHandling { get { return true; } }
        readonly int Padding = 0;

        public AmountConverter(int padding)
        {
            Padding = padding;
        }

        public override string FieldToString(object from)
        {
            String s = String.Empty; // space before (looks pretty)
            if (from == null) { return " ".PadLeft(Padding); }

            decimal num = (decimal)from;
            
            // Zero is blank
            if (num == 0) { return " ".PadLeft(Padding); }

            // Thousand separators for large numbers
            //if (num >= 10000) { return num.ToString(" #,##0.00").PadLeft(Padding); }

            // Normal case
            return (" " + num.ToString("0.00")).PadLeft(Padding);
        }

        public override object StringToField(string from)
        {
            if (from == null) { return 0m; }
            
            from = from.Trim();
            if (String.IsNullOrEmpty(from)) { return 0m; }
            
            return decimal.Parse(from, CultureInfo.InvariantCulture);
        }
    }

    /// <summary>
    /// Converts an arbitrary decimal, with padding support.
    /// </summary>
    class DecimalConverter : ConverterBase
    {
        readonly int Padding = 0;

        protected override bool CustomNullHandling { get { return true; } }

        public DecimalConverter(int padding)
        {
            Padding = padding;
        }

        public override string FieldToString(object from)
        {
            if (from == null) { return " ".PadLeft(Padding); }

            decimal num = (decimal)from;
            return (" " + num.ToString()).PadLeft(Padding);
        }

        public override object StringToField(string from)
        {
            if (from == null) { return 0m; }

            from = from.Trim();
            if (String.IsNullOrEmpty(from)) { return 0m; }

            return decimal.Parse(from, CultureInfo.InvariantCulture);
        }
    }

    /// <summary>
    /// Converts a date, to ISO format. 
    /// One minute precision. Omits the time if it's 00:00.
    /// When parsing, handles @now and @-n @+n (+/- n days)
    /// </summary>
    class DateConverter : ConverterBase
    {
        const String Format = "yyyy-MM-ddTHH:mm";
        const String FormatDayOnly = "yyyy-MM-dd";

        protected override bool CustomNullHandling { get { return true; } }

        public override string FieldToString(object from)
        {
            if (from == null) { return new String(' ', Format.Length+1); }

            DateTime date = (DateTime)from;
            return FieldToString(date);
        }

        public static string FieldToString(DateTime date)
        {
            if (date == date.Date)
            {
                return " " + date.ToString(FormatDayOnly) + "      ";
            }
            return " " + date.ToString(Format); 
        }

        public override object StringToField(string from)
        {
            from = from.Trim();

            // Will readjust to previous tx's date (since it's less than it)
            if (from == "") { return DateTime.MinValue; }

            // One-time 
            if (from.Equals("@now")) { return DateTime.Now; } // now, with time as well
            if (from.Sw("@")) // @ is today, @-1 is yesterday etc.
            {
                int daysOffset = 0;
                if (int.TryParse(from.Substring(1), out daysOffset))
                {
                    return DateTime.Today.AddDays(daysOffset);
                }
                return DateTime.Today;
            }

            DateTime date;
            if (DateTime.TryParseExact(from, FormatDayOnly, CultureInfo.InvariantCulture, 
                DateTimeStyles.None, out date))
            {
                return date;
            }

            // TODO: be more flexible in accepting different formats
            return DateTime.ParseExact(from, Format, CultureInfo.InvariantCulture);
        }
    }

    class StringConverter : ConverterBase
    {
        readonly int Padding = 0;

        public StringConverter() { }

        public StringConverter(int padding)
        {
            Padding = padding;
        }

        public override string FieldToString(object from)
        {
            String s = String.Empty;
            if (from != null) { s = from.ToString(); }
            if (!s.StartsWith(" ")) { s = " " + s; } // space before (looks pretty)

            return s.PadRight(Padding);
        }

        public override object StringToField(string from)
        {
            return from.Trim();
        }


    }
}
